from dataclasses import dataclass
from dataclasses_json import dataclass_json
from typing import Any, List, Callable, Optional
from lib.log import logger
from lib import snapshot


@dataclass_json
@dataclass
class FormItem(object):
    type: str
    title: str = None
    name: str = None
    value: Any = None


@dataclass_json
@dataclass
class StringItem(FormItem):
    type: str = "string"


@dataclass_json
@dataclass
class TextItem(FormItem):
    type: str = "text"


@dataclass_json
@dataclass
class NumberItem(FormItem):
    type: str = "number"


@dataclass_json
@dataclass
class FileItem(FormItem):
    type: str = "file"


@dataclass_json
@dataclass
class DirectoryItem(FormItem):
    type: str = "directory"


@dataclass_json
@dataclass
class SelectItem(FormItem):
    options: List[str] = None
    type: str = "select"


@dataclass_json
@dataclass
class UserSelectItem(FormItem):
    username_field: str = "username"
    password_field: str = "password"
    type: str = "user"


class Flow(object):
    retry = False

    def precheck(self):
        pass

    def __init__(self) -> None:
        super().__init__()

    def set_retry(self, retry):
        self.retry = retry

    def prefun(self):
        # Do something pre
        pass

    def generate(self):
        pass

    def run(self):
        pass

    def afterfun(self):
        # do somethong else
        pass


import time


class MultDataFlow(Flow):
    def __init__(self):
        super().__init__()
        ts = time.strftime('%Y%m%d%H%M%S', time.localtime(time.time()))
        self.taskid = f"{self.__class__.__name__}-{ts}"

    def reset(self):
        pass

    def run(self):
        self.load_data()
        self.prefun()
        item = self.generate()
        logger.info(f"{item}开始执行")
        err_list = []
        err_count = 0
        while item:
            if self.retry:
                # 如果是重试的流程, 则跳过之前已经成功的步骤
                s = snapshot.is_success(self.__class__.__name__, item)
                if s:
                    logger.info("已成功记录,自动跳过")
                    item = self.generate()
                    continue
            try:
                self.run_job(item)
                snapshot.save_check_point(self.taskid, item)
                snapshot.set_success(self.__class__.__name__, item)
            except Exception as e:
                logger.exception(e, stack_info=True)
                err_list.append(f"{item}:{e}")
                if len(err_list) > err_count:
                    snapshot.save_error(self.taskid, err_list)
                self.reset()

            item = self.generate()
        if len(err_list) > 0:
            f = snapshot.save_error(self.taskid, err_list)
            logger.info(f"执行错误[{len(err_list)}个], 保存在: {f}")
        else:
            logger.info("全部执行成功")
        self.afterfun()
        return err_list

    def load_data(self):
        pass

    def prefun(self):
        # Do something pre
        pass

    def generate(self):
        # sub class must impl 
        return None

    def run_job(self, item):
        # sub class must impl
        # raise NotImplemented()
        pass

    def afterfun(self):
        # do somethong else
        pass


class ListDataFlow(MultDataFlow):
    def load_list(self):
        return []

    def load_data(self):
        self.items = self.load_list()
        self.cur_index = 0

    def generate(self):
        if self.cur_index >= len(self.items):
            return None
        item = self.items[self.cur_index]
        self.cur_index += 1
        return item
    
    def row2dict(self, row, toprow):
        d = {}
        for i in range(0, len(row)):
            d[toprow[i]] = row[i]
        return d

@dataclass_json
@dataclass
class ScriptDef(object):
    group: str
    title: str
    arguments: List[FormItem]
    name: Optional[str] = None
    cls: Optional[Any] = None
    func: Optional[Callable] = None
    description: Optional[str] = None
    

